home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / NCSA / tn3270 2.3d26 source / tn3270 / vmxfer.c < prev    next >
Text File  |  1991-03-31  |  36KB  |  1,561 lines

  1. /*
  2.  *  tn3270 for the Macintosh Source Code
  3.  *  Brown University Computing and Information Services
  4.  *  Version 2.3d21, January 17, 1991
  5.  *  Copyright (c) 1988, 1989, 1990, 1991 by Brown University and by
  6.  *  Peter John DiCamillo.
  7.  *
  8.  *  Permission is granted to any individual or institution to use, copy,
  9.  *  or redistribute the binary version of this software and its
  10.  *  documentation provided this notice and the copyright notices are
  11.  *  retained.  Permission is granted to any individual or non-profit
  12.  *  institution to use, copy, modify, or redistribute the source files
  13.  *  of this software provided this notice and the copyright notices are
  14.  *  retained.  This software may not be distributed for profit, either
  15.  *  in original form or in derivative works, nor can the source be
  16.  *  distributed to other than an individual or a non-profit institution.
  17.  *  Any  individual or group interested in seeing and/or using these
  18.  *  source files but who are prevented from doing so by the above
  19.  *  constraints should contact Don Wolfe, Assistant Vice-President for
  20.  *  Computer Systems at Brown University, (401) 863-7250, for possible
  21.  *  software licensing of the source developed at Brown.
  22.  *
  23.  *  Brown University and Peter John DiCamillo make no representations
  24.  *  about the suitability of this software for any purpose.
  25.  *
  26.  *  BROWN UNIVERSITY AND PETER JOHN DICAMILLO GIVE NO WARRANTY, EITHER
  27.  *  EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION PROVIDED,
  28.  *  INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY AND
  29.  *  WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
  30.  *
  31.  */
  32.  
  33. #define __SEG__ vmxfer
  34. #include "maclib.h"
  35. #include <fcntl.h>
  36. #include "termdef.h"
  37. #define eofErr -39
  38. #define    IAC 255                /* Telnet: interpret as command: */
  39.  
  40. vmprt prtinfo = {    /* defaults if VMPR 128 resource is not present */
  41.     4,                            /* fontnum */
  42.     10,                            /* pointsize */
  43.     12,                            /* leading */
  44.     132,                        /* linewidth */
  45.     4,                            /* tabsize */
  46.     57,                            /* pagelength */
  47.     59,                            /* pagelencc */
  48.     14,                            /* top */
  49.     2,                            /* headmarg */
  50.     12,                            /* left */
  51.     0,                            /* leftcc */
  52.     74,                            /* titlewidth */
  53.     0, 0, 0, 0};                /* unused fields */
  54. char * currvname();
  55. DateTimeRec wdate;
  56. char statbuf[80];
  57. char ropen, wopen;            /* flags indicating file open for rd/wr */
  58. unsigned char * rbuf;        /* received data */
  59. unsigned char * sbuf;        /* data sent as reply */
  60. short rlen;                    /* size of rbuf */
  61. short slen;                    /* size of sbuf */
  62. char vmxbgn;                /* xfer mode active flag */
  63. char vmxsub;                /* xfer subset mode active flag */
  64. char kabort;                /* "keyboard" abort flag */
  65. char binxf;                    /* binary mode file transfer */
  66. char mbinxf;                /* MacBinary file transfer */
  67. char prtxf;                    /* downloading print file */
  68. char prtcc;                    /* print file has carriage control */
  69. char prpgopen;                /* print page open */
  70. char prdocopen;                /* print document open */
  71. char cmpstate;                /* state for compression */
  72. char prevchar;                /* previous character for compression */
  73. char crcok;                    /* true if crc has been appended */
  74. char xlflag;                /* true if XL command has been recieved */
  75. short xfspeed;                /* file transfer character rate */
  76. short rfd, wfd;                /* read & write file descriptors */
  77. short wfd_r;                    /* MacBinary resource fork descriptor */
  78. short vnum;                    /* volume descriptor for RMAC/WMAC */
  79. char macFName[258];            /* complete Mac file name */
  80. char macVName[29];            /* Mac volume name */
  81.                             /* both have length byte followed by
  82.                                C string */
  83. unsigned int cursiz;        /* number of sectors transferred */
  84. unsigned int filsiz;        /* total number of sectors */
  85. char statname[14];            /* "uploading" or "downloading" */
  86. char prtbuf2[120];            /* message buffers */
  87. char prtbuf3[120];
  88. char prtbuf4[120];
  89. struct mbhdr {                /* MacBinary header */
  90.     unsigned char         ver;        /* version byte */
  91.     unsigned char        fnlen;        /* length of filename */
  92.     unsigned char        fn[63];        /* filename */
  93.     unsigned char        ftyp[4];    /* file type */
  94.     unsigned char        fcreat[4];    /* file creator */
  95.     unsigned char        flags;        /* finder flags */
  96.     unsigned char        flags2;        /* second flag byte */
  97.     unsigned char        vpos[2];    /* vertical position */
  98.     unsigned char        hpos[2];    /* horizontal position */
  99.     unsigned char        id[2];        /* window or folder ID */
  100.     unsigned char        pflag;        /* "protected" flag */
  101.     unsigned char        zero2;        /* zero */
  102.     unsigned char        dataln[4];    /* data fork length */
  103.     unsigned char        rscln[4];    /* resource fork length */
  104.     unsigned char        crdate[4];    /* creation date */
  105.     unsigned char        mddate[4];    /* last modified date */
  106.     unsigned char        zero3[29];    /* zero fill */
  107.     } mh;
  108. long mbdbmax;                /* MacBin data size in blocks */
  109. long mbrbmax;                /* MacBin resource size in blocks */
  110. long mbdsize;                /* MacBin data fork length */
  111. long mbrsize;                /* MacBin resource fork size */
  112. long mbdextra;                /* MacBin data fork padding */
  113. long mbrextra;                /* MacBin resource fork padding */
  114.  
  115. extern char int_active;        /* interrupt routine running */
  116. extern char serflg;            /* serial connection */
  117. extern char tcpflg;            /* 0 = PC Net; 1 = TCP/IP */
  118. extern char xdlg;
  119. extern DialogPtr xdlgptr;
  120. extern struct GrafPort *myWindow;
  121. extern struct Point sfppoint, sfgpoint;
  122. extern THPrint hPrint;        /* print record handle */
  123. extern char prtinit;        /* flag for printing intialization */
  124. extern char csnlname[];
  125. extern unsigned char **nl_handle;    /* handle to current language mapping */
  126. extern unsigned char nltab[];        /* national language translation table */
  127. extern settings_list cs;
  128. static TPPrPort prtport;
  129. long atol();
  130. long chartolong();
  131. OSErr prtwrite();
  132.  
  133. vmxfer()
  134. {
  135.  
  136. /* In xfer mode, the Mac program acts as a slave to VM/370,
  137.    executing each command from VM (a command may include data
  138.    to be processed) and returning a return code or data block. */
  139.  
  140. register short c;            /* variable for i/o calls */
  141. register short i;            /* loop counter */
  142. short rmax;                    /* count for uncompress loop */
  143. char rchk[5];                /* received checksum string */
  144. char cchk[5];                /* computed checksum string */
  145. char cmdok;                    /* if true, command is ok */
  146.  
  147. /* process a command from VM */
  148.  
  149. slen = 0;
  150. if ((rlen==2) && (rbuf[0]==XFBGN) && (rbuf[1]==XFBGN)) {
  151.     xfrst();
  152.     vmxbgn = 1;            /* set xfer mode */
  153.     xfdlg(0);
  154.     return;
  155.     }
  156.  
  157. if (!vmxbgn) {
  158.     sbuf[slen++] = ' ';
  159.     return;
  160.     }
  161.  
  162. if ((rlen==1) && (rbuf[0]==DC4)) {        /* subset code */
  163.     if (vmxsub) {
  164.         if (xdlg) SelectWindow(xdlgptr);
  165.         }
  166.     else SelectWindow(myWindow);
  167.     vmxsub ^= 1;
  168.     if (serflg || tcpflg) newstat();
  169.     else if (!int_active) newstat();
  170.     return;
  171.     }
  172.  
  173. /* process compressed data */
  174. if ((rlen > 6) && (rbuf[0] == 0x18)) {
  175.     movmem(rbuf+1, sbuf, rlen-1);    /* copy data without prefix */ 
  176.     cmpstate = 0;
  177.     rmax = rlen-6;            /* length without prefix or CRC */
  178.     rlen = 0;
  179.     for (i=0; i < rmax; i++) datachr(&rlen, sbuf[i]);
  180.     while(i < rmax+5) rbuf[rlen++] = sbuf[i++];    /* append CRC */
  181.     }
  182.  
  183. /* verify data read is valid; if not, set cmdok FALSE */
  184.  
  185. if ((rlen > 6) &  (rlen < 2320)) {
  186.     rbuf[rlen] = '\0';                /* delimit received checksum */
  187.     strcpy(rchk,rbuf+rlen-4);        /* copy checksum */
  188.     rbuf[rlen-5] = '\0';            /* delimit data */
  189.     rlen -= 5;                        /* rlen = data length */
  190.     chkdata(rbuf,rlen,cchk);        /* calculate data checksum */         
  191.     cmdok = (strcmp(rchk,cchk) == 0);  /* compare checksums */
  192.     }
  193. else cmdok = 0;
  194.  
  195. /*  If command is ok, return the result of attempting to execute
  196.     it. If the command is in error, just transmit a blank. */
  197.  
  198. if (cmdok) {
  199.     crcok = 0;                        /* no CRC yet */
  200.     excmmd();                        /* execute command */
  201.     if (crcok == 0) {                /* append CRC if needed */
  202.         if (slen == 0) slen = strlen(sbuf);    /* get data length */
  203.         chkdata(sbuf,slen,cchk);        /* get checksum */
  204.         sbuf[slen] = CD;                /* delimit checksum */
  205.         movmem(cchk, sbuf+slen+1, 4);    /* append checksum */
  206.         slen += 5;                        /* update length */
  207.         }
  208.     }
  209. else sbuf[slen++] = ' ';
  210. }
  211.  
  212. chkdata(buf,len,chk)
  213. register char *buf, *chk;
  214. register short len;
  215. {
  216. register char i;
  217. unsigned short crcf();
  218.  
  219. /* calculate four-byte ASCII checksum for buf in chk */
  220.  
  221. sprintf(chk,"%4x",crcf(buf,len,0));
  222. for (i = 0; i < 4; i++)            /* convert blanks to zeros */
  223.     if (chk[i] == ' ') chk[i] = '0';
  224.     else chk[i] = toupper(chk[i]);
  225. }
  226.  
  227. excmmd()
  228. {
  229. register unsigned short i;
  230. i = (rbuf[0] << 8) + rbuf[1];
  231. switch(i) {
  232.     case 0x4f49:        /* 'OI' */
  233.         rdopen();
  234.         break;
  235.     case 0x4249:        /* 'BI' */
  236.         rdopen();
  237.         break;
  238.     case 0x5242:        /* 'RB' */
  239.         rdblock();
  240.         break;
  241.     case 0x4349:        /* 'CI' */
  242.         rdclose();
  243.         break;
  244.     case 0x4f4f:        /* 'OO' ASCII Output (old WMAC) */
  245.     case 0x414f:        /* 'AO' Alternate Output (new WMAC) */
  246.     case 0x424f:        /* 'BO' Binary Output (new WMAC) */
  247.     case 0x4d4f:        /* 'MO' MacBinary Output (new WMAC) */
  248.     case 0x4d48:        /* 'MH' MacBinary Header (new WMAC) */
  249.         wropen();
  250.         break;
  251.     case 0x5742:        /* 'WB' */
  252.         wrblock();
  253.         break;
  254.     case 0x434f:        /* 'CO' */
  255.         wrclose();
  256.         break;
  257.     case 0x4558:        /* 'EX' */
  258.         exitcmd();
  259.         break;
  260.     case 0x5652:        /* 'VR' */
  261.         verscmd();
  262.         break;
  263.     case 0x5454:        /* 'TT' */
  264.         trtime();
  265.         break;
  266.     case 0x584c:        /* 'XL' */
  267.         xlcmd();
  268.         break;
  269.     default:
  270.         setrc(28);
  271.         break;
  272.     }
  273. }
  274.  
  275. setrc(code)
  276. register short code;
  277. {
  278. register char i;
  279. sprintf(sbuf,"RC%4d",code);
  280. for (i = 2; i < 6; i++)
  281.     if (sbuf[i] == ' ') sbuf[i] = '0';
  282. }
  283.  
  284. rdopen()
  285. {
  286. short rdlast;
  287. short rdvnum;
  288. register short rc;
  289. register char nomenu, rdcancel;
  290. long fsize;
  291. struct DateTimeRec fdate;
  292.  
  293. rdcancel = 0;
  294. nomenu = 0;                        /* handle menu option */
  295. rdlast = strlen(rbuf+2) + 1;
  296. if (rbuf[rdlast] == '*') {
  297.     rbuf[rdlast] = 0;
  298.     nomenu = 1;
  299.     }
  300. binxf = (rbuf[0] == 'B');
  301. rc = -1;            /* simulate open error for menu */
  302. ropen = 0;
  303. if (nomenu) {
  304.     strcpy(macVName+1,currvname());    /* get default volume */
  305.     macVName[0] = strlen(macVName+1);
  306.     strcpy(macFName+1,rbuf+2);        /* get file id */
  307.     macFName[0] = strlen(macFName+1);
  308.     rc = fsrdopen(macFName+1, vnum, &rfd);
  309.     }
  310. if (rc != 0) {                /* get id from user */
  311.     getrd(macFName);
  312.     if (macFName[0] == 0) rdcancel = 1;
  313.     if (!rdcancel)
  314.         rc = fsrdopen(macFName+1, vnum, &rfd);
  315.     }
  316. if (rc != 0) {
  317.     if (!rdcancel) stoperr(300);
  318.     setrc(1);
  319.     return;
  320.     }
  321. if (rc == 0) ropen = 1;
  322. strcpy(statname,"Uploading");
  323. getinfo(&fsize,&fdate);
  324. filsiz = (fsize + 127) >> 7;
  325. cursiz = 0;
  326. strcpy(sbuf,"AT");                /* success: return file attributes */
  327. if (binxf) sbuf[0] = 'B';        /* use BT for binary transfer */
  328. sprintf(sbuf+2,"%04x",filsiz);    /* file size */
  329. sprintf(sbuf+6,"%04d%02d%02d%02d%02d%02d",    /* date */
  330.     fdate.year,fdate.month,fdate.day,fdate.hour,
  331.     fdate.minute,fdate.second);
  332. }
  333.  
  334. rdclose()
  335. {
  336. ropen = 0;
  337. if (FSClose(rfd) != 0) setrc(1);     /* close input file */
  338.     else {
  339.         FlushVol(0L, vnum);
  340.         setrc(0);
  341.     }
  342. }
  343.  
  344. rdblock()
  345. {
  346. short rc, rdlen, padlen;
  347. register short i, reccnt;
  348. char blkstr[5], eof, trflg, padchr;
  349. register unsigned char c, maxchar;
  350. unsigned long recnum, r_byte;
  351. short iaccount, dest, src;
  352. char cchk[5];                /* computed checksum string */
  353.  
  354. if (kabort) {            /* set rc 11 for subset/abort */
  355.     setrc(11);
  356.     kabort = 0;
  357.     return;
  358.     }
  359.  
  360. /* give error 3 if block number and speed not read */
  361. if (rlen < 10) {
  362.     setrc(3);
  363.     return;
  364.     }
  365.  
  366. /* extract xfspeed and save */
  367. movmem(rbuf+6,blkstr,4);
  368. blkstr[4] = '\0';
  369. xfspeed = atoi(blkstr);
  370.  
  371. /* extract block number and convert to record */
  372. movmem(rbuf+2,blkstr,4);
  373. blkstr[4] = '\0';
  374. recnum = atol(blkstr);            /* record = block * 18 */
  375. recnum *= 18;
  376.  
  377. /* read 18 records (2304 bytes) or less at end of file */
  378. strcpy(sbuf,"DB");        /* store data block prefix */
  379. typstat();
  380.  
  381. r_byte = recnum << 7;            /* byte offset = record * 128 */
  382. rc = SetFPos(rfd, 1, r_byte);    /* position for read */
  383. if (rc == eofErr) {                /* rc 1 for eof */
  384.     setrc(1);
  385.     return;
  386.     }
  387. else if (rc != 0) {
  388.     stoperr(301);
  389.     setrc(8);
  390.     return;
  391.     }
  392. r_byte = 2304;                    /* read next 2304 bytes of data */
  393. rc = FSRead(rfd, &r_byte, sbuf+2);
  394. if ((rc != eofErr) && (rc != 0)) {    /* check for errors */
  395.     stoperr(301);
  396.     setrc(9);
  397.     return;
  398.     }
  399. if (r_byte == 0) {        /* assume eof if zero bytes read */
  400.     setrc(1);
  401.     return;
  402.     }
  403. rdlen = r_byte;
  404. padlen = 128 - (rdlen % 128);    /* pad to a multiple of 128 */
  405. if (binxf) padchr = 0;
  406. else padchr = CPMEOF;
  407. if (padlen < 128) {
  408.     rdlen += 2;
  409.     for (i=0; i < padlen; i++) sbuf[rdlen++] = padchr;
  410.     rdlen -= 2;
  411.     }
  412. if (binxf) slen = rdlen+2;
  413. else sbuf[rdlen+2] = '\0';
  414. reccnt = rdlen >> 7;    /* no. of 128-byte blocks */
  415. if (reccnt > 0) cursiz = recnum + reccnt;
  416.  
  417. /* For TCP/IP binary transfer, quoting must be inserted for the IAC
  418.    character (X'FF') by replacing each IAC by two of them  */
  419.  
  420. if (binxf && tcpflg) {
  421.     /* append CRC before changing data */
  422.     chkdata(sbuf,slen,cchk);        /* get checksum */
  423.     sbuf[slen] = CD;                /* delimit checksum */
  424.     movmem(cchk, sbuf+slen+1, 4);    /* append checksum */
  425.     slen += 5;                        /* update length */
  426.     crcok = 1;                        /* tell mainline CRC done */
  427.  
  428.     /* now handle IAC characters */
  429.     iaccount = 0;
  430.     for (i=2; i < slen; i++) { 
  431.         if (sbuf[i] == IAC) iaccount++;
  432.         }
  433.     if (iaccount == 0) return;
  434.     dest = slen + iaccount - 1;
  435.     src = slen - 1;
  436.     slen += iaccount;
  437.     while (iaccount > 0) {
  438.         sbuf[dest--] = c = sbuf[src--];
  439.         if (c == IAC) {
  440.             sbuf[dest--] = IAC;
  441.             iaccount--;
  442.             }
  443.         }
  444.     return;
  445.     }
  446.     
  447. if (binxf) return;
  448.  
  449. /* translate invalid characters to "|" and display file
  450.    data on terminal */
  451.  
  452. eof = trflg = 0;
  453. rdlen += 2;
  454. /* versions of RMAC/WMAC which issue the XL command also support Macintosh
  455.    extended ASCII, and can translate characters through X'DE' */
  456. if (xlflag) maxchar = 222;
  457. else maxchar = 126;
  458. for (i = 2; i < rdlen; i++) {
  459.     if (eof) {
  460.         sbuf[i] = '\0';
  461.         break;
  462.         }
  463.     c = sbuf[i];
  464.     switch (c) {
  465.         case TAB:
  466.         case LF:
  467.         case FF:
  468.                     break;
  469.         case CR:
  470.                     sbuf[i] = VT;
  471.                     break;
  472.         case CPMEOF:
  473.                     eof = 1;
  474.                     break;
  475.         case DEL:
  476.                     trflg = 1;
  477.                     sbuf[i] = '|';
  478.                     break;
  479.         default:
  480.                     if ((c < 32) || (c > maxchar)) {
  481.                         trflg = 1;
  482.                         sbuf[i] = '|';
  483.                         }
  484.                     break;
  485.         }
  486.     }
  487.  
  488. if (trflg) stoperr(302);
  489. }
  490.  
  491. typstat()                /* output transfer status */
  492. {
  493. char tofrom[5];
  494. short i;
  495. unsigned percent, min, sec, ovrhead;
  496. long lcvt, lchar, curbytes, totbytes;
  497.  
  498. curbytes = (long)cursiz << 7;
  499. totbytes = (long)filsiz << 7;
  500. lcvt = cursiz;
  501. percent = (lcvt*100)/filsiz;
  502. if (prtxf) {
  503.     sprintf(statbuf, "%s '%s'", statname, macFName+1);
  504.     }
  505. else {
  506.     if (statname[0] == 'D') strcpy(tofrom,"to");
  507.     else strcpy(tofrom,"from");
  508.     sprintf(statbuf,"%s '%s' %s '%s'", statname, macFName+1,
  509.         tofrom, macVName+1);
  510.     }
  511. sprintf(prtbuf2,"%ld/%ld (%d%%)", curbytes, totbytes, percent);
  512. if (xfspeed == 0) {
  513.     sprintf(prtbuf3,"");
  514.     sprintf(prtbuf4,"??:??");
  515.     }
  516. else {
  517.     ovrhead = (filsiz-cursiz+7)/8;    /* no. of rb/wb cmmds. */
  518.     if (statname[0] == 'D') ovrhead *= 30;
  519.                        else ovrhead *= 26;
  520.     lchar = filsiz - cursiz;    /* get total character count */
  521.     lchar <<= 7;
  522.     lchar += ovrhead;        /* plus overhead */
  523.     lcvt = xfspeed;
  524.     sec = lchar/lcvt;        /* get seconds */
  525.     min = sec / 60;
  526.     sec = sec % 60;
  527.     sprintf(prtbuf3,"%d",xfspeed);
  528.     sprintf(prtbuf4,"%d:%02d",
  529.             min,sec);
  530.     }
  531. xfdlg(1,statbuf,prtbuf2,prtbuf3,prtbuf4);
  532. }
  533.  
  534. wropen()
  535. {
  536. char cvtbuff[5];
  537. register char c;
  538. short rdlast;
  539. register short rc;
  540. unsigned short i;
  541. register unsigned long freeBytes, totBytes;
  542. VolumeParam pb;
  543. struct DateTimeRec fdate;
  544. int year, month, day, hour, minute, second;
  545. static char nomenu;
  546. char mhcmd;
  547. HFileParam pbf;
  548. GrafPtr gp;
  549. static char listingft1[] = "listing";
  550. static char listingft2[] = "LISTING";
  551. static long minus1 = -1;
  552.  
  553. mhcmd = (rbuf[0] == 'M') && (rbuf[1] == 'H');
  554. if (mhcmd) {
  555.     movmem(rbuf+2, &mh, 128);    /* save header */
  556.     if ((mh.fnlen == 0) || (mh.fnlen > 63)) {
  557.         stoperr(303);
  558.         setrc(64);        /* check for valid fn length */
  559.         return;
  560.         }
  561.     ptoc(&mh.fnlen);    /* convert filename to C format */
  562.     mbdsize = chartolong(mh.dataln);  /* get lengths of forks */
  563.     mbrsize = chartolong(mh.rscln);
  564.     mbdbmax = (mbdsize+127) >> 7;    /* get block counts */
  565.     mbrbmax = (mbrsize+127) >> 7;
  566.     mbdextra = (mbdbmax << 7) - mbdsize;    /* get padding counts */
  567.     mbrextra = (mbrbmax << 7) - mbrsize;
  568.     }
  569. else {            /* if not MH, get info. from rbuf */
  570.                     /* set nomenu or prtxf flag */
  571.     nomenu = 0;
  572.     prtxf = 0;
  573.     rdlast = strlen(rbuf+20) + 19;
  574.     if (rbuf[rdlast] == '*') {
  575.         rbuf[rdlast] = 0;
  576.         nomenu = 1;
  577.         }
  578.     else if (rbuf[rdlast] == '.') {
  579.         rbuf[rdlast] = 0;
  580.         prtxf = 1;
  581.         }
  582.                     /* get file size */
  583.     movmem(rbuf+2,cvtbuff,4);
  584.     cvtbuff[4] = '\0';
  585.     sscanf(cvtbuff,"%x",&filsiz);
  586.                     /* get file date and time */
  587.     sscanf(rbuf+6,"%4d%2d%2d%2d%2d%2d",
  588.             &year,&month,&day,&hour,
  589.             &minute,&second);
  590.     fdate.year = year;
  591.     fdate.month = month;
  592.     fdate.day = day;
  593.     fdate.hour = hour;
  594.     fdate.minute = minute;
  595.     fdate.second = second;
  596.     fdate.dayOfWeek = 0;
  597.     wdate = fdate;
  598.     }
  599.  
  600. if ((rbuf[0] == 'M') && (rbuf[1] == 'O')) {
  601.                 /* finish MO processing */
  602.     binxf = mbinxf = 1;
  603.     prtxf = 0;
  604.     strcpy(sbuf,"MT");
  605.     return;
  606.     }
  607.                 /* set binxf, mbinxf for all but "MO" */
  608. if (rbuf[1] == 'O') {
  609.     binxf = (rbuf[0] == 'B');
  610.     mbinxf = 0;
  611.     }
  612.  
  613.                 /* get file id to use */
  614. if (!prtxf) {
  615.     if (nomenu) {
  616.         strcpy(macVName+1, currvname());
  617.         macVName[0] = strlen(macVName+1);
  618.         if (mhcmd) strcpy(macFName+1, &mh.fnlen);
  619.         else strcpy(macFName+1,rbuf+20);
  620.         macFName[0] = strlen(macFName+1);
  621.         /* check if file already exists */
  622.         rc = FSOpen(macFName+1, vnum, &wfd);
  623.         if (rc == 0) {
  624.                 setrc(1);
  625.                 FSClose(wfd);
  626.                 FlushVol(0L, vnum);
  627.                 return;
  628.                 }
  629.         }
  630.     else if (mhcmd) getwr(&mh.fnlen, macFName);
  631.                 else getwr(rbuf+20, macFName);
  632.     if (strlen(macFName) == 0) {
  633.         setrc(5);
  634.         return;
  635.         }
  636.     }
  637. else {
  638.     strcpy(macFName+1, rbuf+20);
  639.     macFName[0] = strlen(macFName+1);
  640.     i = macFName[0] - strlen(listingft1);
  641.     if (i >= 2)
  642.         prtcc = (strcmp(listingft1, macFName+i+1) == 0) ||
  643.                 (strcmp(listingft2, macFName+i+1) == 0);
  644.     else
  645.         prtcc = 0;
  646.     prtwrite(&minus1, 0L);    /* prtwrite initialization */
  647. }
  648.     
  649. /* now ready to use file id */
  650.  
  651. if (!prtxf) {
  652.     /* initialize for file calls */
  653.     setmem(&pbf, sizeof(HFileParam), 0);
  654.  
  655.     /* delete any existing file */
  656.     pbf.ioNamePtr = (StringPtr)macFName;
  657.     pbf.ioVRefNum = vnum;
  658.     PBDelete(&pbf, 0);
  659.  
  660.     /* create new file */
  661.     rc = PBCreate(&pbf, 0);
  662.     if (rc != 0) {
  663.         stoperr(303);
  664.         setrc(2);
  665.         return;
  666.         }
  667.  
  668.     /* set finder info */
  669.     rc = PBGetFInfo(&pbf, 0);
  670.     if (rc != 0) {
  671.         stoperr(303);
  672.         setrc(2);
  673.         return;
  674.         }
  675.                         /* set finder flags */
  676.     if (mbinxf) {
  677.         i = mh.flags;
  678.         i <<= 8;
  679.         pbf.ioFlFndrInfo.fdFlags &= 0x00ff;
  680.         pbf.ioFlFndrInfo.fdFlags |= i;
  681.         pbf.ioFlFndrInfo.fdFlags &= 0xf8ff;
  682.         }
  683.     else pbf.ioFlFndrInfo.fdFlags &= 0xfeff;
  684.                         /* set type and creator */
  685.     if (mbinxf) {
  686.         movmem(mh.ftyp, &pbf.ioFlFndrInfo.fdType, 4);
  687.         movmem(mh.fcreat, &pbf.ioFlFndrInfo.fdCreator, 4);
  688.         }
  689.     else {
  690.         pbf.ioFlFndrInfo.fdType = 'TEXT';
  691.         pbf.ioFlFndrInfo.fdCreator = cs.text_creator;
  692.         }
  693.     rc = PBSetFInfo(&pbf, 0);
  694.     if (rc != 0) {
  695.         stoperr(303);
  696.         setrc(2);
  697.         return;
  698.         }
  699.  
  700.     /* open data fork */
  701.     setmem(&pbf, sizeof(HFileParam), 0);
  702.     pbf.ioNamePtr = (StringPtr)macFName;
  703.     pbf.ioVRefNum = vnum;
  704.     pbf.filler1 = fsWrPerm;        /* ioPermssn */
  705.     rc = PBOpen(&pbf, 0);
  706.     if (rc != 0) {
  707.         stoperr(303);
  708.         setrc(2);
  709.         return;
  710.         }
  711.     else wfd = pbf.ioFRefNum; 
  712.  
  713.     /* open resource fork if MacBinary */
  714.     if (mbinxf) {
  715.         rc = PBOpenRF(&pbf, 0);
  716.         if (rc != 0) {
  717.             stoperr(303);
  718.             setrc(2);
  719.             return;
  720.             }
  721.         else wfd_r = pbf.ioFRefNum; 
  722.         }
  723.     }
  724. else {
  725.     if (hPrint == 0) {
  726.         stoperr(305);
  727.         setrc(2);
  728.         return;
  729.         }
  730.     arrowcursor();
  731.     if (prtinit == 0) {
  732.         PrOpen();
  733.         PrintDefault(hPrint);
  734.         prtinit = 1;
  735.         }
  736.     if (!PrJobDialog(hPrint)) {
  737.         setrc(5);
  738.         return; 
  739.         }
  740.     GetPort(&gp);
  741.     setdoctitle(macFName+1);
  742.     prtport = PrOpenDoc(hPrint, 0L, 0L);
  743.     SetPort(gp);
  744.     prdocopen = 1;        /* document now open */
  745.     }
  746. wopen = 1;
  747. if (binxf && (!mbinxf)) strcpy(sbuf,"BT");
  748. else setrc(0);
  749. if (prtxf) strcpy(statname, "Printing"); 
  750. else strcpy(statname,"Downloading");
  751. if (!prtxf) {
  752.     pb.ioCompletion = 0;
  753.     pb.ioNamePtr    = 0;
  754.     pb.ioVRefNum    = vnum;
  755.     pb.ioVolIndex = 0;
  756.     PBGetVInfo(&pb, 0);
  757.     freeBytes = pb.ioVFrBlk * pb.ioVAlBlkSiz;
  758.     totBytes = (long) filsiz << 7;
  759.     if (freeBytes < totBytes) {
  760.         totBytes = (totBytes - freeBytes + 1023) >> 10;
  761.         dFullAlt((short) totBytes);
  762.         FSClose(wfd);
  763.         if (mbinxf) FSClose(wfd_r);
  764.         FSDelete(macFName+1, vnum);
  765.         setrc(99);
  766.         return;
  767.         }
  768.     }
  769. cursiz = 0;
  770. typstat();
  771. }
  772.  
  773. wrclose()
  774. {
  775. short rc1, rc2;
  776.  
  777. wopen = 0;
  778. if (!prtxf) {
  779.     rc1 = FSClose(wfd);
  780.     if (mbinxf) rc2 = FSClose(wfd_r);
  781.     else rc2 = 0;
  782.     if ((rc1 != 0) || (rc2 != 0)) {
  783.         FlushVol(0L, vnum);
  784.         stoperr(304);
  785.         setrc(1);
  786.         }
  787.     else {
  788.         rc1 = settime(&wdate, &mh);
  789.         setrc(rc1);
  790.         FlushVol(0L, vnum);
  791.         }
  792.     }
  793. else setrc(xfprtclose());
  794. }
  795.  
  796. int xfprtclose()
  797. {
  798. int rc;
  799. TPrStatus prStatus;
  800. static long minus3 = -3;
  801. GrafPtr gp;
  802.  
  803. prtwrite(&minus3, 0L);        /* termination call */
  804. GetPort(&gp);
  805. if (prpgopen) {
  806.     SetPort(prtport);
  807.     PrClosePage(prtport);
  808.     }
  809. if (prdocopen) {
  810.     SetPort(prtport);
  811.     PrCloseDoc(prtport);
  812.     if (((*hPrint)->prJob.bJDocLoop == bSpoolLoop) && (PrError() == noErr))
  813.         PrPicFile(hPrint, 0L, 0L, 0L, &prStatus);
  814.     if (PrError() != noErr) {
  815.         stoperr(305);
  816.         rc = 1;
  817.         }
  818.     else rc = 0;
  819.     }
  820. else rc = 0;
  821. SetPort(gp);
  822. prtxf = prpgopen = prdocopen = 0;
  823. return(rc);
  824. }
  825.  
  826. wrblock()
  827. {
  828. register short i, reccnt;
  829. register short padlen;
  830. short typlen, bufwrite();
  831. char blkstr[5], c;
  832. unsigned long recnum, w_byte;
  833. OSErr rc;
  834.  
  835. if (kabort) {            /* set rc 11 for subset/abort */
  836.     setrc(11);
  837.     kabort = 0;
  838.     return;
  839.     }
  840.  
  841. /* rbuf should contain: WBnnnnssssxxxx..., where "nnnn" is
  842.    the block number, "ssss" is the transfer speed in cps,
  843.    and "xxxx..." is the data to write. */
  844.  
  845. /* give error 3 if block number and speed not read */
  846. if (rlen < 10) {
  847.     setrc(3);
  848.     return;
  849.     }
  850.  
  851. /* translate SO, VT to CR, LF */
  852.  
  853. typlen = rlen - 10;
  854. if (!binxf) for (i=0; i < typlen; i++) {
  855.     c = rbuf[i+10];
  856.     switch (c) {
  857.         case CPMEOF:    /* ignore EOF char */
  858.                     break;
  859.         case SO:        /* SO is translated CR */
  860.                     rbuf[i+10] = CR;
  861.                     break;
  862.         case VT:        /* VT is translated LF */
  863.                     rbuf[i+10] = LF;
  864.                     break;
  865.         case FF:
  866.                     break;
  867.         default:
  868.                     break;
  869.                 }
  870.         }
  871.  
  872. /* extract xfspeed and save */
  873. movmem(rbuf+6,blkstr,4);
  874. blkstr[4] = '\0';
  875. xfspeed = atoi(blkstr);
  876.  
  877. /* extract block number and convert to record */
  878. movmem(rbuf+2,blkstr,4);
  879. blkstr[4] = '\0';
  880. recnum = atol(blkstr);            /* record = block * 18 */
  881. recnum *= 18;
  882.  
  883. /* assume eof if < 2304 bytes to write; pad with EOF char
  884.    to make a multiple of 128 bytes */
  885.  
  886. padlen = 128 - ((rlen-10) % 128);
  887. if (binxf) {
  888.     if (padlen < 128) reccnt = (padlen+rlen-10) >> 7;
  889.     else reccnt = (rlen-10) >> 7;
  890.     }
  891. else {
  892.     if (padlen < 128)
  893.         for (i=0; i < padlen; i++) rbuf[rlen++] = CPMEOF;
  894.     reccnt = (rlen-10) >> 7; /* divide by 128 to get block count */
  895.     }
  896.  
  897. /* return now if no blocks to write (should only happen at eof) */
  898.  
  899. if (reccnt == 0) {
  900.     setrc(0);
  901.     return;
  902.     }
  903.  
  904. /* for a text file, delete trailing EOF characters */
  905.  
  906. if (!binxf) {
  907.     rlen--;            /* convert length to rbuf offset */
  908.     while (rlen >= 10) {
  909.         if (rbuf[rlen] != CPMEOF) break;
  910.         rlen--;
  911.         }
  912.     rlen++;        /* convert back to length */
  913.     if (rlen == 10) {    /* return if only EOF characters */
  914.         setrc(0);
  915.         return;
  916.         }
  917.     }
  918.  
  919. /* write data to disk. give return code 4 for an error */
  920.  
  921. if ((!mbinxf) && (!prtxf)) {
  922.     w_byte = recnum << 7;          /* get byte offset */
  923.     rc = SetFPos(wfd, 1, w_byte);
  924.     if (rc != 0) {
  925.         stoperr(304);
  926.         setrc(4);
  927.         return;
  928.         }
  929.     }
  930. w_byte = rlen-10;
  931. if (mbinxf) rc = mbwrite(&w_byte, rbuf+10, recnum);
  932. else if (prtxf) rc = prtwrite(&w_byte, rbuf+10);
  933.      else rc = FSWrite(wfd, &w_byte, rbuf+10);
  934. if ((rc != 0) || (w_byte != rlen-10)) {
  935.     if (prtxf) stoperr(305);
  936.     else stoperr(304);
  937.     setrc(5);
  938.     return;
  939.     }
  940. setrc(0);
  941. cursiz = recnum + reccnt;
  942. typstat();
  943. }
  944.  
  945. exitcmd()        /* exit command */
  946. {
  947. setrc(0);
  948. xfrst();
  949. }
  950.  
  951. verscmd()        /* return version info */
  952. {
  953. strcpy(sbuf,"VIM0231");        /* Mac3270 version 2.31 */
  954.                 /* append national language name */
  955. strcat(sbuf, ":");
  956. strcat(sbuf, csnlname);
  957. }
  958.  
  959. xlcmd()        /* return national language translation info. */
  960. {
  961. unsigned char *sptr;
  962. register short i, x, j;
  963.  
  964. xlflag = 1;
  965. strcpy(sbuf, "XI");            /* translation info */
  966. sptr = sbuf+2;
  967. if (nl_handle != 0) {
  968.     for (i=0; i < 256; i++) {
  969.         x = nltab[i];
  970.         if (x != i) {
  971.             sprintf(sptr, "%02x%02x", i, x);
  972.             for (j=0; j < 4; j++) {
  973.                 sptr[j] = toupper(sptr[j]);
  974.                 }
  975.             sptr += 4;
  976.             }
  977.         }
  978.     }
  979. }
  980.  
  981. trtime()        /* read and display new transfer time */
  982. {
  983. char blkstr[5];
  984.  
  985. /* extract xfspeed and save */
  986. movmem(rbuf+2,blkstr,4);
  987. blkstr[4] = '\0';
  988. xfspeed = atoi(blkstr);
  989.  
  990. /* display new status */
  991. typstat();
  992.  
  993. /* return normal rc */
  994. setrc(0);
  995. }
  996.  
  997. getrd(macname)
  998. register char *macname;
  999. {
  1000.     Point where;
  1001.     unsigned short (*fileFilter)();
  1002.     register short numTypes;
  1003.     SFTypeList typeList;
  1004.     ProcPtr dlgHook;
  1005.     SFReply reply;
  1006.     VolumeParam pbrec;
  1007.     register VolumeParam * _pbrec;
  1008.     pascal unsigned short onlydata();
  1009.  
  1010.     _pbrec = &pbrec;
  1011.     where = sfgpoint;
  1012.     dlgHook = 0;
  1013.     fileFilter = onlydata;
  1014.     numTypes = -1;
  1015.     arrowcursor();
  1016.     SFGetFile(&where,"",fileFilter,numTypes,
  1017.         typeList, dlgHook, &reply);
  1018.     macname[0] = macname[1] = '\0';
  1019.     if (reply.good == 0) return;
  1020.     macname[0] = reply.fName.length;
  1021.     strcpy(macname+1, ptoc(&reply.fName));
  1022.     vnum = reply.vRefNum;
  1023.  
  1024.     pbrec.ioCompletion = 0;
  1025.     pbrec.ioVRefNum = vnum;
  1026.     pbrec.ioVolIndex = 0;
  1027.     pbrec.ioNamePtr = (StringPtr)macVName;
  1028.     PBGetVInfo(_pbrec, 0);
  1029.     macVName[1+macVName[0]] = '\0';
  1030. }
  1031.  
  1032. pascal unsigned short onlydata(_pb)
  1033. FileParam * _pb;
  1034. {
  1035. if (_pb->ioFlLgLen == 0L) return(0x100);
  1036.     else return(0);
  1037. }
  1038.  
  1039. getwr(suggid,macname)
  1040. register char * suggid;
  1041. register char *macname;
  1042. {
  1043.     Point where;
  1044.     ProcPtr dlgHook;
  1045.     SFReply reply;
  1046.     VolumeParam pbrec;
  1047.     VolumeParam * _pbrec;
  1048.  
  1049.     _pbrec = &pbrec;
  1050.     where = sfppoint;
  1051.     dlgHook = 0;
  1052.     /* ctop(suggid); */
  1053.     arrowcursor();
  1054.     SFPutFile(&where,"Save downloaded file as:",
  1055.         suggid,dlgHook,&reply);
  1056.     /* ptoc(suggid); */
  1057.     macname[0] = macname[1] = '\0';
  1058.     if (reply.good == 0) return;
  1059.     macname[0] = reply.fName.length;
  1060.     strcpy(macname+1, ptoc(&reply.fName));
  1061.     vnum = reply.vRefNum;
  1062.  
  1063.     pbrec.ioCompletion = 0;
  1064.     pbrec.ioVRefNum = vnum;
  1065.     pbrec.ioVolIndex = 0;
  1066.     pbrec.ioNamePtr = (StringPtr)macVName;
  1067.     PBGetVInfo(_pbrec, 0);
  1068.     macVName[1+macVName[0]] = '\0';
  1069. }
  1070.  
  1071. char * currvname()
  1072. {
  1073. static char rtnvol[28];
  1074. VolumeParam pb;
  1075. OSErr rc;
  1076.  
  1077. pb.ioCompletion = 0;
  1078. pb.ioNamePtr = (StringPtr)rtnvol;
  1079. pb.ioVRefNum = vnum;
  1080. pb.ioVolIndex = 0;
  1081. rc = PBGetVInfo(&pb, 0);
  1082. if (rc == 0) ptoc(rtnvol);
  1083. else GetVol(rtnvol, &vnum);
  1084. return(rtnvol);
  1085. }
  1086.  
  1087. getinfo(fsize, fdate)
  1088. register long * fsize;
  1089. struct DateTimeRec * fdate;
  1090. {
  1091. FileParam fblk;
  1092. register FileParam * _fblk;
  1093.  
  1094. _fblk = &fblk;
  1095. fblk.ioCompletion = 0;
  1096. fblk.ioNamePtr = (StringPtr)macFName;
  1097. fblk.ioVRefNum = vnum;
  1098. fblk.ioFVersNum = 0;
  1099. fblk.ioFDirIndex = 0;
  1100. PBGetFInfo(_fblk,0);
  1101. *fsize = fblk.ioFlLgLen;
  1102. Secs2Date(fblk.ioFlMdDat, fdate);
  1103. }
  1104.  
  1105. settime(fdate, mh)
  1106. register struct DateTimeRec * fdate;
  1107. struct mbhdr * mh;
  1108. {
  1109. FileParam fblk;
  1110. long crsecs, mdsecs;
  1111. OSErr rc;
  1112.  
  1113. setmem(&fblk, sizeof(FileParam), 0);
  1114. fblk.ioNamePtr = (StringPtr)macFName;
  1115. fblk.ioVRefNum = vnum;
  1116. rc = PBGetFInfo(&fblk,0);
  1117. if (rc != 0) return(rc+200);
  1118. Date2Secs(fdate, &fblk.ioFlMdDat);
  1119. Date2Secs(fdate, &fblk.ioFlCrDat);
  1120. if (mbinxf) {
  1121.     crsecs = chartolong(mh->crdate);
  1122.     mdsecs = chartolong(mh->mddate);
  1123.     if ((crsecs != 0) && (mdsecs != 0)) {
  1124.         fblk.ioFlMdDat = mdsecs;
  1125.         fblk.ioFlCrDat = crsecs;
  1126.         }
  1127.     }
  1128. rc = PBSetFInfo(&fblk,0);
  1129. if (rc != 0) return(rc+300);
  1130. else return(0);
  1131. }
  1132.  
  1133. xfrst()
  1134. {
  1135. short rc;
  1136. if (prtxf) xfprtclose();
  1137. else {
  1138.     if (ropen) if (FSClose(rfd) == 0) FlushVol(0L, vnum);
  1139.     if (wopen) {
  1140.         rc = FSClose(wfd);
  1141.         if ((rc == 0)  && mbinxf) rc = FSClose(wfd_r);
  1142.         if (rc == 0) FlushVol(0L, vnum);
  1143.         }
  1144.     }
  1145. xfdlg(2);
  1146. xfinit();
  1147. }
  1148.  
  1149. xfinit()
  1150. {
  1151. vmxsub = vmxbgn = 0;
  1152. kabort = 0;
  1153. ropen = wopen = 0;
  1154. xfspeed = 0;
  1155. xdlg = 0;
  1156. prtxf = 0;
  1157. prdocopen = 0;
  1158. prpgopen = 0;
  1159. xlflag = 0;
  1160. if (myWindow != 0) {
  1161.     if (serflg || tcpflg) newstat();
  1162.     else if (!int_active) newstat();
  1163.     }
  1164. }
  1165.  
  1166. datachr(rdoff, c)
  1167. short * rdoff;
  1168. unsigned char c;
  1169. {
  1170. short count, max;
  1171.  
  1172. switch(cmpstate) {
  1173.     case 0:                        /* normal character */
  1174.         if (c == 0x18) cmpstate = 1;
  1175.         else {
  1176.             rbuf[(*rdoff)++] = c;
  1177.             prevchar = c;
  1178.             }
  1179.         break;
  1180.     case 1:                        /* after x'18' */
  1181.         if (c == 0x18) {            /* literal x'18' */
  1182.             rbuf[(*rdoff)++] = c;
  1183.             prevchar = c;
  1184.             }
  1185.         else {                        /* compression count */
  1186.             count = (c - 0x20) + 2;
  1187.             max = 2320 - (*rdoff);
  1188.             if (count > max) count = max;
  1189.             while (count > 0) {
  1190.                 rbuf[(*rdoff)++] = prevchar;
  1191.                 count--;
  1192.                 }
  1193.             }
  1194.         cmpstate = 0;
  1195.         break;
  1196.     default:
  1197.         break;
  1198.     }
  1199. }
  1200.  
  1201. long chartolong(str)
  1202. char * str;
  1203. {
  1204. union {
  1205.     char s[4];
  1206.     long l;
  1207.     } u;
  1208.  
  1209. movmem(str, u.s, 4);
  1210. return(u.l);
  1211. }
  1212.  
  1213. mbwrite(count, data, offset)
  1214. long * count;
  1215. char * data;
  1216. unsigned long offset;
  1217. {
  1218. long bcnt, tsize, wsize;
  1219. short rc;
  1220. char * newdata;
  1221. long newcount;
  1222. long mbdbcnt, mbrbcnt, mbtotal;
  1223. long pos;
  1224.  
  1225. /* set block counts file block offset */
  1226.  
  1227. mbtotal = mbdbmax + mbrbmax;
  1228. if (offset > mbtotal) return(999);
  1229. if ((offset == mbtotal) && ((*count) != 0)) return(998);
  1230.  
  1231. if (offset >= mbdbmax) {
  1232.     mbdbcnt = 0;
  1233.     mbrbcnt = mbtotal - offset;
  1234.     }
  1235. else {
  1236.     mbdbcnt = mbdbmax - offset;
  1237.     mbrbcnt = mbrbmax;
  1238.     }
  1239.  
  1240. bcnt = ((*count) + 127) >> 7;
  1241. if (bcnt > (mbdbcnt + mbrbcnt)) bcnt = mbdbcnt + mbrbcnt;
  1242. if (bcnt == 0) return(0);
  1243. newdata = data;        /* init. data for resource fork */
  1244. newcount = (*count);
  1245. if (mbdbcnt > 0) {
  1246.     if (bcnt <= mbdbcnt) {    /* all blocks in data fork */
  1247.         wsize = bcnt << 7;
  1248.         if (bcnt == mbdbcnt) wsize -= mbdextra;
  1249.         tsize = wsize;
  1250.         if (wsize <= (*count)) {
  1251.             pos = (mbdbmax - mbdbcnt) << 7;
  1252.             rc = SetFPos(wfd, 1, pos); 
  1253.             if (rc == 0) rc = FSWrite(wfd, &wsize, data);
  1254.             }
  1255.         else rc = -999; 
  1256.         if ((rc == 0) && (wsize == tsize)) return(0);
  1257.         else {
  1258.             (*count) = 0;
  1259.             return(rc);
  1260.             }
  1261.         }
  1262.     else {                    /* blocks for resource fork too */
  1263.         wsize = mbdbcnt << 7;
  1264.         newdata = data + wsize;
  1265.         newcount = (*count) - wsize;
  1266.         wsize -= mbdextra;
  1267.         tsize = wsize;
  1268.         pos = (mbdbmax - mbdbcnt) << 7;
  1269.         rc = SetFPos(wfd, 1, pos);
  1270.         if (rc == 0) rc = FSWrite(wfd, &wsize, data);
  1271.         if ((rc == 0) && (wsize == tsize)) bcnt -= mbdbcnt;
  1272.         else {
  1273.             (*count) = 0;
  1274.             return(rc);
  1275.             }
  1276.         }
  1277.     }
  1278.  
  1279. /* all remaining blocks for resource fork */
  1280. wsize = bcnt << 7;
  1281. if (bcnt == mbrbcnt) wsize -= mbrextra;
  1282. tsize = wsize;
  1283. if (wsize <= newcount) {
  1284.     pos = (mbrbmax - mbrbcnt) << 7;
  1285.     rc = SetFPos(wfd_r, 1, pos);
  1286.     if (rc == 0) rc = FSWrite(wfd_r, &wsize, newdata);
  1287.     }
  1288. else rc = -999; 
  1289. if ((rc == 0) && (wsize == tsize)) {
  1290.     mbrbcnt -= bcnt;
  1291.     return(0);
  1292.     }
  1293. else {
  1294.     (*count) = 0;
  1295.     return(rc);
  1296.     }
  1297. }
  1298.  
  1299. OSErr prtwrite(count, addr)
  1300. long * count;
  1301. unsigned char * addr;
  1302. {
  1303. static char newline1[MAXLINEWIDTH+2];    /* extra space for cc and null */
  1304. static char newline2[MAXLINEWIDTH+2];    
  1305. static short prtlen, prtlen1, prtlen2;
  1306. static char nextcc;
  1307. static long minus1 = -1;
  1308. static long minus2 = -2;
  1309. static long minus3 = -3;
  1310. unsigned short c, i, j;
  1311.  
  1312. if (((*count) == 0) || ((*count) < -3)) return(0);
  1313.  
  1314. if (((*count) == -1) || ((*count) == -2)) {        /* initialization calls */
  1315.     setmem(newline1, MAXLINEWIDTH+2, ' ');            /* -1 for new page */
  1316.     setmem(newline2, MAXLINEWIDTH+2, ' ');            /* -2 for new line */
  1317.     if (prtcc) prtlen = prtlen1 = prtlen2 = 0;
  1318.     else prtlen = prtlen1 = prtlen2 = 1;
  1319.     if ((*count) == -1) nextcc = '1';
  1320.     else nextcc = ' ';
  1321.     return(0);
  1322.     }
  1323.  
  1324. if ((*count) == -3) {                            /* termination call */
  1325.     if (prtcc) {
  1326.         if (prtlen1 > 0) {
  1327.             newline1[prtlen1] = 0;
  1328.             prtline(newline1);
  1329.             }
  1330.         }
  1331.     else {
  1332.         if (prtlen1 > 1) {
  1333.             newline1[0] = nextcc;
  1334.             nextcc = '+';
  1335.             newline1[prtlen1] = 0;
  1336.             prtline(newline1);
  1337.             }
  1338.         if (prtlen2 > 1) {
  1339.             newline2[0] = nextcc;
  1340.             nextcc = '+';
  1341.             newline2[prtlen2] = 0;
  1342.             prtline(newline2);
  1343.             }
  1344.         }
  1345.     return(0);
  1346.     }
  1347.  
  1348. for (i = 0; i < (*count); i++) {
  1349.     c = addr[i];
  1350.     if (prtcc)
  1351.         switch(c) {
  1352.             case TAB:
  1353.                 if (prtlen1 < prtinfo.linewidth+1) prtlen1++;
  1354.                 while ((((prtlen1-1) % prtinfo.tabsize) != 0) &&
  1355.                        ((prtlen1-1) < prtinfo.linewidth+1))
  1356.                     prtlen1++;
  1357.                 break;
  1358.             case CR:
  1359.                 if (prtlen1 == 0) newline1[prtlen1++] = ' ';
  1360.                 prtwrite(&minus3, 0L);
  1361.                 prtwrite(&minus2, 0L);
  1362.                 break;
  1363.             default:
  1364.                 if (prtlen1 < prtinfo.linewidth+1)
  1365.                     newline1[prtlen1++] = c;
  1366.                 break;
  1367.             }
  1368.     else
  1369.         switch (c) {
  1370.             case BS:
  1371.                 if (prtlen > 1) prtlen--;
  1372.                 break;
  1373.             case CR:
  1374.                 if ((prtlen1 == 1) && (prtlen2 == 1))
  1375.                     newline1[prtlen1++] = ' ';
  1376.                 prtwrite(&minus3, 0L);
  1377.                 prtwrite(&minus2, 0L);
  1378.                 break;
  1379.             case LF:
  1380.                 j = prtlen;
  1381.                 if ((prtlen1 == 1) && (prtlen2 == 1))
  1382.                     newline1[prtlen1++] = ' ';
  1383.                 prtwrite(&minus3, 0L);
  1384.                 prtwrite(&minus2, 0L);
  1385.                 prtlen = j;
  1386.                 break;
  1387.             case FF:
  1388.                 prtwrite(&minus3, 0L);
  1389.                 prtwrite(&minus1, 0L);
  1390.                 prtlen1 = 2;
  1391.                 break;
  1392.             case TAB:
  1393.                 if (prtlen < prtinfo.linewidth+1) prtlen++;
  1394.                 while ((((prtlen-1) % prtinfo.tabsize) != 0) && 
  1395.                        ((prtlen-1) < prtinfo.linewidth+1))
  1396.                     prtlen++;
  1397.                 break;
  1398.             default:
  1399.                 if (prtlen < prtinfo.linewidth) {
  1400.                     if (newline1[prtlen] == ' ') {
  1401.                         newline1[prtlen++] = c;
  1402.                         if (prtlen > prtlen1) prtlen1 = prtlen;
  1403.                         }
  1404.                     else if (newline2[prtlen] == ' ') {
  1405.                         newline2[prtlen++] = c;
  1406.                         if (prtlen > prtlen2) prtlen2 = prtlen;
  1407.                         }
  1408.                     else {
  1409.                         j = prtlen;
  1410.                         prtwrite(&minus3, 0L);
  1411.                         prtwrite(&minus2, 0L);
  1412.                         nextcc = '+';
  1413.                         prtlen = j;
  1414.                         newline1[prtlen++] = c;
  1415.                         if (prtlen > prtlen1) prtlen1 = prtlen;
  1416.                         }
  1417.                     }
  1418.                 break;
  1419.             }
  1420.     }
  1421. return(0);
  1422. }
  1423.  
  1424. prtline(s)
  1425. unsigned char *s;
  1426. {
  1427. static int lineoffset, tt1len, pgnum;
  1428. GrafPtr gp;
  1429. char newpage;
  1430. int initskip, slen, leftoff, pglen;
  1431. static char tt1[MAXLINEWIDTH+1];
  1432. static char tt2[MAXLINEWIDTH+1];
  1433. int i;
  1434. char pbuff[12];
  1435.  
  1436. slen = strlen(s);
  1437. if (slen < 1) return;        /* should never happen */
  1438.  
  1439. GetPort(&gp);
  1440. SetPort(prtport);
  1441.  
  1442. newpage = 0;
  1443.  
  1444. if (prtcc) {
  1445.     leftoff = prtinfo.leftcc;
  1446.     pglen = prtinfo.pagelencc;
  1447.     }
  1448. else {
  1449.     leftoff = prtinfo.left;
  1450.     pglen = prtinfo.pagelength;
  1451.     }
  1452.  
  1453. if (prpgopen == 0) {        /* initial call for a new file */
  1454.     lineoffset = pglen;
  1455.     newpage = 1;
  1456.     initskip = 1;
  1457.     pgnum = 0;
  1458.     maketitles(tt1, tt2, &tt1len);
  1459.     }
  1460.  
  1461. switch(s[0]) {                /* interpret carriage control */
  1462.     case '0':
  1463.         lineoffset += 2;
  1464.         initskip = lineoffset - pglen;
  1465.         if (initskip > 0) newpage = 1;
  1466.         break;
  1467.     case '-':
  1468.         lineoffset += 3;
  1469.         initskip = lineoffset - pglen;
  1470.         if (initskip > 0) newpage = 1;
  1471.         break;
  1472.     case '+':
  1473.         break;
  1474.     case '1':
  1475.         initskip = 1;
  1476.         newpage = 1;
  1477.         break;
  1478.     default:
  1479.         lineoffset ++;
  1480.         initskip = lineoffset - pglen;
  1481.         if (initskip > 0) newpage = 1;
  1482.         break;
  1483.     }
  1484.  
  1485. if (newpage) {
  1486.     if (prpgopen) PrClosePage(prtport);
  1487.     PrOpenPage(prtport, 0L);
  1488.     prpgopen = 1;
  1489.     TextFont(prtinfo.fontnum);
  1490.     TextSize(prtinfo.pointsize);
  1491.     PicComment(155, 0, 0L);        /* line layout off */
  1492.     lineoffset = 0;
  1493.     pgnum++;
  1494.     if (!prtcc) {
  1495.         setmem(tt1+tt1len, prtinfo.titlewidth-tt1len, 0x20);
  1496.         if (pgnum > 999) sprintf(pbuff, "Page%4d", pgnum%10000);
  1497.         else sprintf(pbuff, "Page %d", pgnum);
  1498.         i = strlen(pbuff);
  1499.         movmem(pbuff, tt1+prtinfo.titlewidth-i, i); 
  1500.         i = prtinfo.titlewidth - tt1len - i - strlen(tt2);
  1501.         if (i >= 4) movmem(tt2, tt1+tt1len+(i/2), strlen(tt2));
  1502.         MoveTo(leftoff, lineoffset*prtinfo.leading+prtinfo.top);
  1503.         DrawText(tt1, 0, prtinfo.titlewidth);
  1504.         lineoffset++;
  1505.         if (i < 4) {
  1506.             MoveTo(leftoff, lineoffset*prtinfo.leading+prtinfo.top);
  1507.             DrawText(tt2, 0, strlen(tt2));
  1508.             lineoffset++;
  1509.             }
  1510.         lineoffset += prtinfo.headmarg;
  1511.         }
  1512.     lineoffset += initskip-1;
  1513.     }
  1514. if (slen > 1) {
  1515.     MoveTo(leftoff, lineoffset*prtinfo.leading+prtinfo.top);
  1516.     DrawText(s+1, 0, slen-1);
  1517.     }
  1518. SetPort(gp);
  1519. }
  1520.  
  1521. maketitles(tt1, tt2, tt1len)
  1522. char *tt1, *tt2;
  1523. int * tt1len;
  1524. {
  1525. short tlen;
  1526. static char * days[7] = {
  1527.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  1528. static char * months[12] = {
  1529.     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
  1530.     "Aug", "Sep", "Oct", "Nov", "Dec"};
  1531. static char am[3] = "AM";
  1532. static char pm[3] = "PM";
  1533. char * timeptr;
  1534. short hours;
  1535. long datesecs;
  1536.  
  1537.                         /* first line */
  1538. setmem(tt1, prtinfo.titlewidth, 0x20);
  1539. tt1[prtinfo.titlewidth] = 0;
  1540. movmem("File: \"", tt1, 7);
  1541. tlen = strlen(macFName+1);
  1542. if (tlen > prtinfo.titlewidth-16) tlen = prtinfo.titlewidth-16;
  1543. movmem(macFName+1, tt1+7, tlen);
  1544. if (tlen < prtinfo.titlewidth-16) {
  1545.     tt1[tlen+7] = '"';
  1546.     (*tt1len) = tlen+8;
  1547.     }
  1548. else (*tt1len) = tlen+7;
  1549.                         /* second line */
  1550. Date2Secs(&wdate, &datesecs);
  1551. Secs2Date(datesecs, &wdate);
  1552. if (wdate.hour < 12) timeptr = am;
  1553. else timeptr = pm;
  1554. if (wdate.hour == 0) hours = 12;
  1555. else if (wdate.hour > 12) hours = wdate.hour - 12;
  1556. else hours = wdate.hour;
  1557. sprintf(tt2, "Last Modified: %s, %s %d, %d  %d:%02d:%02d %s",
  1558. days[wdate.dayOfWeek-1], months[wdate.month-1], wdate.day, wdate.year,
  1559. hours, wdate.minute, wdate.second, timeptr);
  1560. }
  1561.